//
//  UITextInput.swift
//  Documentation
//
//  Created by Toj on 12/29/22.
//

// MARK: - UITextInput
public protocol UITextInput : UIKeyInput {
    
    // 根据文本内容 得到range范围的内容
    @available(iOS 3.2, *)
    func text(in range: UITextRange) -> String?
    
    // 当前内容 替换range范围的内容为 text
    @available(iOS 3.2, *)
    func replace(_ range: UITextRange, withText text: String)

    
  // 选择某段文本内容, range: from 与to 一致, 光标索引位置
    @NSCopying var selectedTextRange: UITextRange? { get set }

    
    /* If text can be selected, it can be marked. Marked text represents provisionally
     * inserted text that has yet to be confirmed by the user.  It requires unique visual
     * treatment in its display.  If there is any marked text, the selection, whether a
     * caret or an extended range, always resides within.
     *
     * Setting marked text either replaces the existing marked text or, if none is present,
     * inserts it from the current selection. */
    
    @available(iOS 3.2, *)
    var markedTextRange: UITextRange? { get } // Nil if no marked text.

    @available(iOS 3.2, *)
    var markedTextStyle: [NSAttributedString.Key : Any]? { get set } // Describes how the marked text should be drawn.

    func setMarkedText(_ markedText: String?, selectedRange: NSRange) // selectedRange is a range within the markedText

    func unmarkText()

    
    /* 文本文档的结束和开始 */
    // 开始位置
    @available(iOS 3.2, *)
    var beginningOfDocument: UITextPosition { get }
    
    // 末尾位置
    @available(iOS 3.2, *)
    var endOfDocument: UITextPosition { get }

    // 开始位置结束位置 创建一个 UITextRange,
    @available(iOS 3.2, *)
    func textRange(from fromPosition: UITextPosition, to toPosition: UITextPosition) -> UITextRange?

    // 根据起始位置, 得到一个偏移后的位置
    @available(iOS 3.2, *)
    func position(from position: UITextPosition, offset: Int) -> UITextPosition?

    @available(iOS 3.2, *)
    func position(from position: UITextPosition, in direction: UITextLayoutDirection, offset: Int) -> UITextPosition?

    
    /* Simple evaluation of positions */
    @available(iOS 3.2, *)
    func compare(_ position: UITextPosition, to other: UITextPosition) -> ComparisonResult

    @available(iOS 3.2, *)
    func offset(from: UITextPosition, to toPosition: UITextPosition) -> Int

    
    /* A system-provided input delegate is assigned when the system is interested in input changes. */
    weak var inputDelegate: UITextInputDelegate? { get set }

    
    /* A tokenizer must be provided to inform the text input system about text units of varying granularity. */
    var tokenizer: UITextInputTokenizer { get }

    
    /* Layout questions. */
    @available(iOS 3.2, *)
    func position(within range: UITextRange, farthestIn direction: UITextLayoutDirection) -> UITextPosition?

    @available(iOS 3.2, *)
    func characterRange(byExtending position: UITextPosition, in direction: UITextLayoutDirection) -> UITextRange?

    
    /* Writing direction */
    @available(iOS 6.0, *)
    func baseWritingDirection(for position: UITextPosition, in direction: UITextStorageDirection) -> NSWritingDirection

    @available(iOS 6.0, *)
    func setBaseWritingDirection(_ writingDirection: NSWritingDirection, for range: UITextRange)

    
    /* Geometry used to provide, for example, a correction rect. */
    @available(iOS 3.2, *)
    func firstRect(for range: UITextRange) -> CGRect

    @available(iOS 3.2, *)
    func caretRect(for position: UITextPosition) -> CGRect

    @available(iOS 6.0, *)
    func selectionRects(for range: UITextRange) -> [UITextSelectionRect] // Returns an array of UITextSelectionRects

    
    /* Hit testing. */
    @available(iOS 3.2, *)
    func closestPosition(to point: CGPoint) -> UITextPosition?

    @available(iOS 3.2, *)
    func closestPosition(to point: CGPoint, within range: UITextRange) -> UITextPosition?

    @available(iOS 3.2, *)
    func characterRange(at point: CGPoint) -> UITextRange?

    
    @available(iOS 6.0, *)
    optional func shouldChangeText(in range: UITextRange, replacementText text: String) -> Bool // return NO to not change text

    
    /* Text styling information can affect, for example, the appearance of a correction rect.
     * Returns a dictionary containing NSAttributedString keys. */
    @available(iOS 3.2, *)
    optional func textStyling(at position: UITextPosition, in direction: UITextStorageDirection) -> [NSAttributedString.Key : Any]?

    
    /* To be implemented if there is not a one-to-one correspondence between text positions within range and character offsets into the associated string. */
    @available(iOS 3.2, *)
    optional func position(within range: UITextRange, atCharacterOffset offset: Int) -> UITextPosition?

    @available(iOS 3.2, *)
    optional func characterOffset(of position: UITextPosition, within range: UITextRange) -> Int

    
    /* An affiliated view that provides a coordinate system for all geometric values in this protocol.
     * If unimplemented, the first view in the responder chain will be selected. */
    @available(iOS 2.0, *)
    optional var textInputView: UIView { get }

    
    /* Selection affinity determines whether, for example, the insertion point appears after the last
     * character on a line or before the first character on the following line in cases where text
     * wraps across line boundaries. */
    optional var selectionAffinity: UITextStorageDirection { get set }

    
    /* This is an optional method for clients that wish to support dictation phrase alternatives. If
     * they do not implement this method, dictation will just insert the most likely interpretation
     * of what was spoken via -insertText:.
     * dictationResult is an array of UIDictationPhrases. */
    @available(iOS 5.1, *)
    optional func insertDictationResult(_ dictationResult: [UIDictationPhrase])

    
    /* These are optional methods for clients that wish to know when there are pending dictation results. */
    optional func dictationRecordingDidEnd()

    optional func dictationRecognitionFailed()

    
    /* The following three optional methods are for clients that wish to support a placeholder for
     * pending dictation results. -insertDictationPlaceholder must return a reference to the
     * placeholder. This reference will be used to identify the placeholder by the other methods
     * (there may be more than one placeholder). */
    optional var insertDictationResultPlaceholder: Any { get }

    optional func frame(forDictationResultPlaceholder placeholder: Any) -> CGRect

    /* willInsertResult will be NO if the recognition failed. */
    optional func removeDictationResultPlaceholder(_ placeholder: Any, willInsertResult: Bool)

    
    // This is an optional method for clients that wish to support text phrase alternatives. If they do not implement this method,
    // the text will be inserted by -insertText: without the phase alternatives.
    optional func insertText(_ text: String, alternatives: [String], style: UITextAlternativeStyle)

    
    // set attributedString as markedText, selectedRange is a range within the markedText
    @available(iOS 3.2, *)
    optional func setAttributedMarkedText(_ markedText: NSAttributedString?, selectedRange: NSRange)

    
    // Insert a placeholder
    // If `size.height` is <= 0, then the placeholder is inline and line height.
    // If `size.height` is > 0, then the placeholder is treated as a paragraph of height `size.height`.
    @available(iOS 13.0, *)
    optional func insertTextPlaceholder(with size: CGSize) -> UITextPlaceholder

    
    // Remove the placeholder.
    @available(iOS 13.0, *)
    optional func remove(_ textPlaceholder: UITextPlaceholder)

    
    /* The following three optional methods are for clients that wish to display a floating cursor to
     * guide user manipulation of the selected text range via the system-provided keyboard. If a client
     * does not implement these methods, user feedback will be limited to the outcome after setting the
     * selected text range using positions resulting from hit testing. */
    @available(iOS 9.0, *)
    optional func beginFloatingCursor(at point: CGPoint)

    @available(iOS 9.0, *)
    optional func updateFloatingCursor(at point: CGPoint)

    @available(iOS 9.0, *)
    optional func endFloatingCursor()
}
